/*
 *   Copyright 2012-present OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

// Packages
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import $ from 'jquery';
import 'jquery-ui/ui/widgets/draggable.js';
import { defer } from 'lodash';
import classnames from 'classnames';
import isEqual from 'react-fast-compare';
import { Tree } from 'antd';
import TruncateString from 'react-truncate-string';

// Utils
import { Saiku, Settings } from '../../../../utils';

// Styles
import './TreeMeasures.css';

// Components
const { TreeNode } = Tree;

class TreeMeasures extends Component {
  componentDidMount() {
    this.handleDraggable();
  }

  shouldComponentUpdate(nextProps, nextState) {
    return !isEqual(this.props.measures, nextProps.measures);
  }

  componentDidUpdate(prevProps, prevState) {
    if (!isEqual(prevProps.measures, this.props.measures)) {
      this.handleDraggable();
    }
  }

  componentWillUnmount() {
    if (this.$rootNode) {
      this.$rootNode.draggable('destroy');
    }
  }

  handleDraggable = () => {
    defer(() => {
      this.$rootNode = $(this.rootNode)
        .find('.sku-measure-item')
        .not('.ui-draggable-disabled');

      this.$rootNode.draggable({
        cancel: '.not-draggable',
        connectToSortable: $('.sku-measures-axis.sku-connectable'),
        containment: $('.sku-query-designer-dialog'),
        cursorAt: { top: 10, left: 85 },
        helper: 'clone',
        opacity: 0.6,
        placeholder: 'placeholder',
        scroll: false,
        tolerance: 'touch',
        start: (event, ui) => {
          const $measureElem = ui.helper.find('.sku-measure-data');

          ui.helper.html($measureElem);
        },
        zIndex: 1000
      });
    });
  };

  onExpandTreeNode = (expandedKeys, { expanded, node }) => {
    if (expanded) {
      this.handleDraggable();
    }
  };

  onSelectTreeNode = (
    selectedKeys,
    { selected, selectedNodes, node, event }
  ) => {
    if (node.props.className === 'sku-measures-group') {
      node.onExpand(event);
      this.handleDraggable();
    }
  };

  renderMeasureItem() {
    const { draggableId } = this.props;
    const measuresGroup = this.props.measures;

    return Object.keys(measuresGroup).map(key => (
      <TreeNode
        key={`sku-${key}-group`}
        className="sku-measures-group"
        title={<TruncateString text={key} />}
      >
        {measuresGroup[key].map(
          (measure, index) =>
            (typeof measure['visible'] === 'undefined' ||
              measure['visible']) && (
              <TreeNode
                key={Saiku.uid(measure.uniqueName)}
                className={classnames('sku-measure-item', {
                  'ui-draggable-disabled': measure.isDragDisabled
                })}
                disabled={measure.isDragDisabled}
                selectable={false}
                title={
                  <span
                    className="sku-measure-data"
                    dragsourceid={draggableId}
                    dragsourceindex={index}
                    title={
                      measure.description
                        ? measure.description
                        : measure.uniqueName
                    }
                    measure={measure.name}
                    measuregroup={measure.measureGroup}
                    type="EXACT"
                  >
                    <TruncateString text={measure.caption} />
                  </span>
                }
              />
            )
        )}
      </TreeNode>
    ));
  }

  render() {
    const defaultExpandedKeys = Settings.MEASURES_GROUP_COLLAPSED
      ? Object.keys(this.props.measures).map(key => `sku-${key}-group`)
      : [];

    return (
      <div
        className="sku-measures-container"
        ref={node => (this.rootNode = node)}
      >
        <Tree
          className="sku-measures-tree"
          onExpand={this.onExpandTreeNode}
          onSelect={this.onSelectTreeNode}
          defaultExpandedKeys={defaultExpandedKeys}
        >
          {this.renderMeasureItem()}
        </Tree>
      </div>
    );
  }
}

TreeMeasures.propTypes = {
  draggableId: PropTypes.string.isRequired,
  measures: PropTypes.object
};

export default TreeMeasures;
